package org.flexthinker.binding.ui.form.binding.support
{
    import flash.events.Event;
    import flash.events.SoftKeyboardEvent;

    import org.flexthinker.binding.bean.Binding;
    import org.flexthinker.binding.form.support.DefaultValidatingFormModel;
    import org.flexthinker.binding.ui.form.binding.MockForm;
    import org.flexthinker.binding.value.support.MockBean;
    import org.hamcrest.assertThat;
    import org.hamcrest.core.throws;
    import org.hamcrest.object.equalTo;
    import org.hamcrest.object.instanceOf;
    import org.hamcrest.object.nullValue;

    import spark.components.Label;
    import spark.components.TextInput;

    public class FormBindingTest
    {
        private var formBinding:FormBinding;
        private var form:MockForm;
        private var bean:MockBean;
        [Bindable]
        private var source:BindingSource;

        public function FormBindingTest()
        {
        }

        [Before]
        public function setUp():void
        {
            form = new MockForm();
            formBinding = new FormBinding(form);

            bean = new MockBean();
            bean.simpleString = "AAA";
            bean.simpleNumber = 111;

            source = new BindingSource();
        }


        [Test]
        public function testAutoBind():void
        {
            source.label = "myLabel";
            source.text = "myText";

            form.label = new Label();
            form.label.needsSoftKeyboard = false;
            form.label.id = "label";

            form.text = new TextInput();
            form.text.needsSoftKeyboard = false;
            form.text.name = "text";

            formBinding.setFormModel( new DefaultValidatingFormModel(source));

            assertThat(formBinding.getBindings().length,equalTo(0));

            // auto bind remaining fields, field name must match model property name
            formBinding.autoBind();
            formBinding.bind();

            assertThat("bindings are not created correctly", formBinding.getBindings().length,equalTo(2));
            assertThat(formBinding.getBindings()[0].isBound, equalTo(true));
            assertThat(formBinding.getBindings()[1].isBound, equalTo(true));

            assertThat(form.label.text, equalTo(source.label));
            assertThat(form.text.text, equalTo(source.text));

            form.label.text = "new label Text";
            form.text.text = "new textInput Text";

            formBinding.getFormModel().commit();
            assertThat("Binding source should change when view changes", source.label , equalTo(form.label.text));
            assertThat("Binding source should change when view changes", source.text, equalTo(form.text.text));

            source.text = "final text";
            source.label = "final label";
            assertThat(form.label.text, equalTo(source.label));
            assertThat(form.text.text, equalTo(source.text));
        }

        [Test]
        public function testWhenNewFieldsAreAddedAfterBind():void
        {
            source.label = "myLabel";
            source.text = "myText";

            form.label = new Label();
            form.label.needsSoftKeyboard = false;
            form.label.id = "label";

            formBinding.setFormModel( new DefaultValidatingFormModel(source));

            assertThat(formBinding.getBindings().length,equalTo(0));

            // auto bind remaining fields, field name must match model property name
            formBinding.autoBind();
            formBinding.bind();

            assertThat("bindings are not created correctly", formBinding.getBindings().length,equalTo(1));

            form.text = new TextInput();
            form.text.needsSoftKeyboard = false;
            form.text.id = "text";
            form.text.text = "textBeforeBinding";
            form.simulatePartAdded("text", form.text);

            assertThat("bindings should include new added fields", formBinding.getBindings().length,equalTo(2));

            assertThat("new binding should be bound",formBinding.getBindings()[1].isBound, equalTo(true) );
            assertThat(form.text.text, equalTo("myText"));

            // fieldRemoved scenario
            form.simulatePartRemoved("label", form.label);
            assertThat("bindings should remove fields that get removed", formBinding.getBindings().length, equalTo(1));
            assertThat( formBinding.getFieldBinder("label"), nullValue() );

            // re-adding the field scenario
            form.label = new Label();
            form.label.needsSoftKeyboard = false;
            form.label.id = "label";
            form.label.text = "beforeBinding";
            form.simulatePartAdded("label", form.label);
            assertThat("bindings should include new added fields", formBinding.getBindings().length,equalTo(2));
            assertThat("new binding should be bound",formBinding.getBindings()[0].isBound, equalTo(true) );
            assertThat("new binding should be bound",formBinding.getBindings()[1].isBound, equalTo(true) );
            assertThat(form.label.text, equalTo(source.label));

            //removing all fields scenarios
            var textBinding:Binding = formBinding.getBindings()[0];
            var labelBinding:Binding = formBinding.getBindings()[1];
            assertThat(textBinding.isBound, equalTo(true));
            assertThat(labelBinding.isBound, equalTo(true));

            form.simulatePartRemoved("label", form.label);
            form.simulatePartRemoved("text", form.text);
            assertThat("bindings should remove fields that get removed", formBinding.getBindings().length, equalTo(0));
            assertThat( formBinding.getFieldBinder("label"), nullValue() );
            assertThat( formBinding.getFieldBinder("text"), nullValue() );
            assertThat(textBinding.isBound, equalTo(false));
            assertThat(labelBinding.isBound, equalTo(false));

        }

        // negative tests
        [Test]
        public function testAutoBindWithNoSource():void
        {
            assertThat( function():void
                        {
                            formBinding.autoBind()
                        }, throws( instanceOf(Error)));
        }

        [Test]
        public function testBindingsAreCreatedOnValidFormFields():void
        {
            source.label = "myLabel";
            source.text = "myText";

            formBinding.setFormModel( new DefaultValidatingFormModel(source));

            formBinding.autoBind();

            formBinding.bind();

            assertThat("bindings shouldn't be created on invalid form fields", formBinding.getBindings().length,equalTo(0));
        }
    }
}

import org.flexthinker.binding.value.support.MockBean;

class BindingSource
{
    [Bindable]
    public var label:String;

    [Bindable]
    public var text:String;

    [Bindable]
    public var item1:MockBean;

    [Bindable]
    public var item2:MockBean;

    public function BindingSource(label:String = null,  text:String = null):void
    {
        this.label = label;
        this.text = text;
    }
}
